/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bea.banana;

import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author user1
 */
public class BananaEngine {

    byte[] block = new byte[8];
    public BananaKey key = new BananaKey();
    ArrayList<byte[]> listplain = new ArrayList<byte[]>();
    ArrayList<byte[]> listcipher = new ArrayList<byte[]>();
    
    private void clearAll() {
        listplain.clear();
        listcipher.clear();
    }

    public void f(byte[] bb, int ii) {
        byte[] k = key.genKeyFeistel(ii);
        for (int j = 0; j < 4; j++) {
            bb[j] = (byte) (bb[j] ^ k[j]);
        }
    }

    public byte[] enkrip() throws Exception{

        byte[] temps = new byte[8];
        for (int g = 0; g < 8; g++) {
            byte[] l = new byte[4];
            byte[] r = new byte[4];
            System.arraycopy(block, 0, l, 0, 4);
            System.arraycopy(block, 4, r, 0, 4);

            for (int i = 0; i < 16; i++) {

                byte[] temp = new byte[r.length];
                System.arraycopy(r, 0, temp, 0, r.length);
                f(r, (i + g));
                for (int j = 0; j < 4; j++) {
                    r[j] = (byte) (r[j] ^ l[j]);
                }

                System.arraycopy(temp, 0, l, 0, temp.length);
                //System.out.println("feistel " + i);
            }
            System.arraycopy(l, 0, block, 0, 4);
            System.arraycopy(r, 0, block, 4, 4);
        }
        System.arraycopy(block, 0, temps, 0, 8);
//        String hasil = new String(temps);
//        System.out.println(hasil);
        return temps;
    }

    public byte[] dekrip() throws Exception{

        byte[] temps = new byte[8];
        for (int g = 1; g < 9; g++) {
            byte[] l = new byte[4];
            byte[] r = new byte[4];
            System.arraycopy(block, 0, l, 0, 4);
            System.arraycopy(block, 4, r, 0, 4);
            for (int i = 23; i > 7; i--) {

                byte[] temp = new byte[l.length];
                System.arraycopy(l, 0, temp, 0, l.length);
                f(l, (i - g));
                for (int j = 0; j < 4; j++) {
                    l[j] = (byte) (l[j] ^ r[j]);
                }
                System.arraycopy(temp, 0, r, 0, temp.length);
                //System.out.println("feistel dekrip k" + i);
            }
            System.arraycopy(l, 0, block, 0, 4);
            System.arraycopy(r, 0, block, 4, 4);
        }
        System.arraycopy(block, 0, temps, 0, 8);
        String hasil = new String(temps);
        System.out.println(hasil);
        return temps;
    }

    public void setplain(byte[] b) {
        clearAll();
        for (int i = 0; i < b.length / 8; i++) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (i * 8), nb, 0, 8);
            listplain.add(nb);
        }

        if (b.length % 8 != 0) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (b.length / 8) * 8, nb, 0, b.length % 8);
            listplain.add(nb);
        }

    }

    public void setcipher(byte[] b) {
        clearAll();
        for (int i = 0; i < b.length / 8; i++) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (i * 8), nb, 0, 8);
            listcipher.add(nb);
        }

        if (b.length % 8 != 0) {
            byte[] nb = new byte[8];
            for (int j = 0; j < 8; j++) {
                nb[j] = 0;
            }
            System.arraycopy(b, (b.length / 8) * 8, nb, 0, b.length % 8);
            listcipher.add(nb);
        }
        
    }

    public byte[] genIV() {

        byte[] IV = new byte[8];
        Random r = new Random();

        for (int i = 0; i < 8; i++) {
            int x = r.nextInt(128);
            IV[i] = (byte) (x);
        }
        return IV;
    }

    public void ecbEncrypt() throws Exception{

        for (int i = 0; i < listplain.size(); i++) {
            byte[] hasiltemp = new byte[8];
            System.arraycopy(listplain.get(i), 0, block, 0, 8);
            hasiltemp = enkrip();
            listcipher.add(hasiltemp);
        }
    }
    
    public void ecbDecrypt() throws Exception {

        for (int i = 0; i < listcipher.size(); i++) {
            byte[] hasiltemp = new byte[8];
            System.arraycopy(listcipher.get(i), 0, block, 0, 8);
            hasiltemp = dekrip();
            listplain.add(hasiltemp);
        }


    }   
    

    public void ofbEncrypt() throws Exception {
        byte[] IV = genIV();
        byte[] antrian = new byte[8];
        byte[] plain = new byte[8];
        byte[] hasiltemp = new byte[8];
        byte[] hasilcipher = new byte[8];
        byte[] temp = new byte[8];
        int i = 0;
        int prev = 0;
        listcipher.add(IV);
        while (i < listplain.size()) {
            hasiltemp = new byte[8];
            hasilcipher = new byte[8];
            plain = new byte[8];
            antrian = new byte[8];
            System.arraycopy(listplain.get(i), 0, plain, 0, 8);
            if (prev == 0) {
                System.arraycopy(IV, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    hasilcipher[j] = (byte) (hasiltemp[0] ^ plain[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasiltemp[0];
                }
                System.arraycopy(hasiltemp, 0, temp, 0, 8);
            } else {
                System.arraycopy(temp, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    hasilcipher[j] = (byte) (hasiltemp[0] ^ plain[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasiltemp[0];
                }
                System.arraycopy(hasiltemp, 0, temp, 0, 8);
            }
            listcipher.add(hasilcipher);
            i++;
            prev++;
        }
    }

    public void ofbDecrypt() throws Exception {
        byte[] IV = listcipher.get(0); //harusnya blok pertama
        byte[] antrian = new byte[8];
        byte[] cipher = new byte[8];
        byte[] hasiltemp = new byte[8];
        byte[] hasilplain = new byte[8];
        byte[] temp = new byte[8];
        int i = 1;
        int prev = -1;
        while (i < listcipher.size()) {
            hasiltemp = new byte[8];
            hasilplain = new byte[8];
            cipher = new byte[8];
            antrian = new byte[8];
            System.arraycopy(listcipher.get(i), 0, cipher, 0, 8);
            if (prev == -1) {
                System.arraycopy(IV, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    hasilplain[j] = (byte) (hasiltemp[0] ^ cipher[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasiltemp[0];
                }
                System.arraycopy(hasiltemp, 0, temp, 0, 8);
            } else {
                System.arraycopy(temp, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    hasilplain[j] = (byte) (hasiltemp[0] ^ cipher[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasiltemp[0];
                }
                System.arraycopy(hasiltemp, 0, temp, 0, 8);
            }
            listplain.add(hasilplain);
            i++;
            prev++;
        }
    }

    public void cfbEncrypt() throws Exception {
        byte[] IV = genIV();
        byte[] antrian = new byte[8];
        byte[] plain = new byte[8];
        byte[] hasiltemp = new byte[8];
        byte[] hasilcipher = new byte[8];
        int i = 0;
        int prev = 0;
        listcipher.add(IV);
        while (i < listplain.size()) {
            hasiltemp = new byte[8];
            hasilcipher = new byte[8];
            plain = new byte[8];
            antrian = new byte[8];
            System.arraycopy(listplain.get(i), 0, plain, 0, 8);
            if (prev == 0) {
                System.arraycopy(IV, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    hasilcipher[j] = (byte) (hasiltemp[0] ^ plain[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasilcipher[j];
                }
            } else {
                System.arraycopy(listcipher.get(prev), 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    hasilcipher[j] = (byte) (hasiltemp[0] ^ plain[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = hasilcipher[j];
                }
            }
            listcipher.add(hasilcipher);
            i++;
            prev++;
        }
    }

    public void cfbDecrypt()  throws Exception{
        byte[] IV = listcipher.get(0); //harusnya blok pertama
        byte[] antrian = new byte[8];
        byte[] cipher = new byte[8];
        byte[] hasiltemp = new byte[8];
        byte[] hasilplain = new byte[8];
        int i = 1;
        int prev = -1;
        while (i < listcipher.size()) {
            hasiltemp = new byte[8];
            hasilplain = new byte[8];
            cipher = new byte[8];
            antrian = new byte[8];
            System.arraycopy(listcipher.get(i), 0, cipher, 0, 8);
            if (prev == -1) {
                System.arraycopy(IV, 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    byte er = cipher[j];
                    hasilplain[j] = (byte) (hasiltemp[0] ^ cipher[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = er;
                }
            } else {
                System.arraycopy(listcipher.get(i - 1), 0, antrian, 0, 8);
                for (int j = 0; j < 8; j++) {
                    System.arraycopy(antrian, 0, block, 0, 8);
                    hasiltemp = enkrip();
                    byte er = cipher[j];
                    hasilplain[j] = (byte) (hasiltemp[0] ^ cipher[j]);
                    byte[] hha = new byte[7];
                    System.arraycopy(antrian, 1, hha, 0, 7);
                    System.arraycopy(hha, 0, antrian, 0, 7);
                    antrian[7] = er;
                }
            }
            listplain.add(hasilplain);
            i++;
            prev++;
        }
    }

    public void cbcEncrypt() throws Exception{
        
        byte[] init = new byte[8];
        byte[] hasiltemp = new byte[8];
        init = genIV();
        listcipher.add(init);
        System.arraycopy(listplain.get(0), 0, block, 0, 8);
        for (int y = 0; y<8; y++){
            block[y] =(byte) (block[y] ^ init[y]);
        }
        hasiltemp = enkrip();
        listcipher.add(hasiltemp);
        for (int z = 1; z<listplain.size(); z++){
            hasiltemp = new byte[8];
            System.arraycopy(listcipher.get(z), 0, block, 0, 8);
            for (int y = 0; y<8; y++){
                block[y] =(byte) (block[y] ^ listplain.get(z)[y]);
            }
            hasiltemp = enkrip();
            listcipher.add(hasiltemp);
        }        
    }
    
    
    public void cbcDecrypt()  throws Exception{
        
        byte[] init;
        byte[] dek;
        init = listcipher.get(0);
        System.arraycopy(listcipher.get(1), 0, block, 0, 8);
        dek = dekrip();
        for (int y = 0; y<8; y++){
            dek[y] =(byte) (dek[y] ^ init[y]);
        }
        listplain.add(dek);
        for (int z = 2; z<listcipher.size(); z++){
            dek = new byte[8];
            System.arraycopy(listcipher.get(z), 0, block, 0, 8);
            dek = dekrip();
            for (int y = 0; y<8; y++){
            dek[y] =(byte) (dek[y] ^ listcipher.get(z-1)[y]);
            }
            listplain.add(dek);
        }        
    }
    
    
    
    
    

    public byte[] gethasil(boolean t) {
        byte[] hasil;
        if (t == true) {
            hasil = new byte[(listcipher.size()) * 8];
            for (int i = 0; i < listcipher.size(); i++) {
                System.arraycopy(listcipher.get(i), 0, hasil, i * 8, 8);
            }
        } else {
            hasil = new byte[(listplain.size()) * 8];
            for (int i = 0; i < listplain.size(); i++) {
                System.arraycopy(listplain.get(i), 0, hasil, i * 8, 8);
            }
        }

        return hasil;
    }

    public static int unsignedByteToInt(byte b) {
        return (int) b & 0xFF;
    }
}